import { Injectable, UnauthorizedException } from '@nestjs/common'
import { PassportStrategy } from '@nestjs/passport'
import { ExtractJwt, Strategy } from 'passport-jwt'
import { ConfigService } from '@nestjs/config'
import { DatabaseService } from '../../database/database.service'
import { JwtPayload, AuthUser } from '../interfaces/jwt-payload.interface'

/**
 * JWT 认证策略
 * 用于验证 JWT Token 并获取用户信息
 */
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    private readonly configService: ConfigService,
    private readonly databaseService: DatabaseService
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get<string>('JWT_SECRET')
    })
  }

  /**
   * 验证 JWT 载荷并返回用户信息
   * @param payload JWT 载荷
   * @returns 认证用户信息
   */
  async validate(payload: JwtPayload): Promise<AuthUser> {
    try {
      // 根据用户ID查找用户
      const user = await this.databaseService.user.findUnique({
        where: { id: payload.sub },
        select: {
          id: true,
          username: true,
          email: true,
          role: true,
          avatar: true,
          isActive: true,
          createdAt: true,
          updatedAt: true
        }
      })

      // 检查用户是否存在
      if (!user) {
        throw new UnauthorizedException('用户不存在')
      }

      // 检查用户是否激活
      if (!user.isActive) {
        throw new UnauthorizedException('用户账户已被禁用')
      }

      // 如果有会话ID，验证会话是否有效
      if (payload.sessionId) {
        const session = await this.databaseService.session.findUnique({
          where: { id: payload.sessionId }
        })

        if (!session || session.expiresAt < new Date()) {
          throw new UnauthorizedException('会话已过期')
        }

        // 更新会话最后访问时间
        await this.databaseService.session.update({
          where: { id: payload.sessionId },
          data: { updatedAt: new Date() }
        })
      }

      return user
    } catch (error) {
      if (error instanceof UnauthorizedException) {
        throw error
      }
      throw new UnauthorizedException('Token 验证失败')
    }
  }
}
